-- UISkyCityRuins
-- Create by cheny3
-- 遗迹主界面

require "game/ui/form/sky_city/UISkyCity"
require "game/ui/form/sky_city/UIRelicStrengthen"
require "game/ui/form/sky_city/UISkyRelicMain"

-- 内部函数
local workerShadowOffset = {{10, -1}, {10, -1}, {10, -1}};    -- 工匠阴影偏移

-- UISkyCityRuins继承自Layer
UISkyCityRuins = class("UISkyCityRuins", function()
    return cc.Layer:create();
end);

function UISkyCityRuins.create()
    return UISkyCityRuins.new();
end

-- 内部参数
local TOTAL_WORKERS = 4;
local EFFECT_WORKERS = 3;
local DUST_NUM = 2;

-- 构造函数
function UISkyCityRuins:ctor()
    -- 合图
    cc.SpriteFrameCache:getInstance():addSpriteFrames("images/ui/workshop_workers.plist");

    -- 初始化
    self:setName("UISkyCityRuins");
    -- 遗迹界面
    local node = cc.CSLoader:createNode("layout/sky_city/SkyCityRuins.csb");
    self:addChild(node);
    self.node = node;

    -- 注册事件处理回调函数
    self:registerEventCallback();

    -- 注册点击事件
    self:registerTouchEvent();

    -- 重绘
    self:redraw();

    -- 检查气泡
    self:checkBtnHint();

    -- 检查采集显隐
    self:checkCollcetShow();

    -- 检查按钮显隐
    self:checkPermitBtn();

    -- 适配
    self:resize();
end

-- 适配
function UISkyCityRuins:resize()
    local node = self.node;

    -- bg置于中间并缩放至合适大小
    AlignM.alignToCenter(node, "bg");

    -- CT居中并缩放至合适大小
    AlignM.alignToCenter(node, "CT");

    -- BT置于底部并缩放至合适大小
    AlignM.alignToBottomCenter(node, "BT");
end

-- 重绘界面
function UISkyCityRuins:redraw()
    self:redrawDefence();
    self:redrawAirShip();
    self:redrawInfo();
    self:redrawSlimes();
    self:redrawRuins();
    self:redrawEffect();
end

-- 绘制额外效果
function UISkyCityRuins:redrawEffect()
    -- 风沙
    local dustNode = findChildByName(self.node, "bg/dust_node");
    for i = 1, DUST_NUM do
        local pos = dustNode:getChildByName("pos" .. i);
        local function effect()
            pos:stopAllActions();
            pos:removeAllChildren();
            playEffect(pos, 1829);
            performWithDelay(pos, effect, 3);
        end
        performWithDelay(pos, effect, i * 2);
    end
end

-- 防御状态部分
function UISkyCityRuins:redrawDefence()
    local defenceNode = findChildByName(self.node, "bg/defence");
    local bubbleNode =  findChildByName(defenceNode, "bubble");
    local bubbleBg = findChildByName(bubbleNode, "bg");
    local bubbleIcon = findChildByName(bubbleNode, "icon");
    local timeLabel =  findChildByName(bubbleNode, "time");
    TextStyleM.setTextStyle(timeLabel, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_ORANGE, true);
    bubbleIcon:setVisible(false);
    timeLabel:setVisible(true);

    local relicInfo = SkyRelicM.getMyRelicInfo();
    local showBubble = false;
    if relicInfo["protect"]
        and tonumber(relicInfo["protect"]) > TimeM.getServerTime() then
        showBubble = true;
    end

    -- 圣坛效果
    local effectNode = findChildByName(defenceNode, "effect_node");
    effectNode:stopAllActions();
    effectNode:removeAllChildren();
    playEffect(effectNode, 1828, -20, -90);

    -- 检查防御状态气泡显示
    if showBubble then
        bubbleNode:setVisible(true);

        local function tick()
            local leftTime = relicInfo["protect"] - TimeM.getServerTime();
            local timeDesc = remainingTimeDesc(leftTime);
            timeLabel:setString(timeDesc);
            if leftTime <= 0 then
                bubbleNode:setVisible(false);
                return;
            end
            performWithDelay(self, tick, 1);
        end
        tick();
        -- 气泡轻微收缩
        bubbleNode:stopAllActions();
        playBubbleAnima(bubbleNode, false, 0.65);
    else
        bubbleNode:setVisible(false);
    end

    local function onBubbleClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_click");
            -- TODO
        end
    end
    AddTouchEventListener(bubbleBg, onBubbleClick);
end

-- 信息部分
function UISkyCityRuins:redrawInfo()
    local infoNode = findChildByName(self.node, "bg/info");
    local slimeNode = findChildByName(infoNode, "slime");
    local bubbleNode = findChildByName(infoNode, "bubble");
    local bubbleBg = findChildByName(bubbleNode, "bg");
    local revengePanel = findChildByName(self.node, "bg/revenge_panel");

    -- 判断是否有复仇信息
    if #SkyRelicM.getRobRecord() > 0 then
        -- 阴影
        slimeNode:removeAllChildren();
        local shadow = ccui.ImageView:create();
        shadow:loadTexture("images/ui/workshop/shadow2.png", 1);
        shadow:setPosition(cc.p(11, -18));
        slimeNode:addChild(shadow);
        -- 哭泣的冈布奥
        playEffect(slimeNode, 1707, 14, 10);
        slimeNode:setScaleX(-0.85);
        slimeNode:setScaleY(0.85);
        -- 气泡轻微收缩
        bubbleNode:stopAllActions();
        playBubbleAnima(bubbleNode, false, 0.80);
        infoNode:setVisible(true);
        revengePanel:setVisible(true);
    else
        slimeNode:removeAllChildren();
        slimeNode:setScale(1);
        -- 阴影
        local shadow = ccui.ImageView:create();
        shadow:loadTexture("images/ui/workshop/shadow2.png", 1);
        shadow:setPosition(cc.p(11, -17));
        slimeNode:addChild(shadow);
        shadow:setScale(0.8);
        -- 微笑的冈布奥
        local slimeImg = ccui.ImageView:create();
        slimeImg:setPosition(cc.p(11, -20));
        slimeImg:loadTexture("images/ui/workshop/new_slime.png", 1);
        slimeImg:setScaleX(-0.8);
        slimeImg:setScaleY(0.8);
        slimeNode:addChild(slimeImg);
        -- 隐藏气泡
        bubbleNode:setVisible(false);
        infoNode:setVisible(true);
        revengePanel:setVisible(true);
        slimeImg:stopAllActions();
        -- 跳跃
        slimeJumpAnimation(slimeImg, cc.p(0, 0), cc.p(0, 0), cc.p(300, 800), cc.p(5, 15));
    end

    local function onBubbleClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_click");
            -- 打开界面
            require "game/ui/form/sky_city/UISkyRevengeMain";
            UIMgr.getCurrentScene():removeFormByName("UISkyRevengeMain");
            local uiForm = UISkyRevengeMain.create();
            UIMgr.getCurrentScene():addForm(uiForm);
        end
    end
    AddTouchEventListener(bubbleBg, onBubbleClick);
    AddTouchEventListener(revengePanel, onBubbleClick);
end

-- 飞船部分
function UISkyCityRuins:redrawAirShip()
    local shipNode = findChildByName(self.node, "bg/ship");
    local panel = findChildByName(self.node, "bg/ship_panel");

    -- 飞船名字
    local shipNameLabel = findChildByName(self.node, "bg/ship_name");
    local shipId = NewAirShipM.getActiveAirShip();
    local shipName = NewAirShipM.query(shipId, "name");
    local iconPath = getAirShipImgPath(NewAirShipM.query(shipId, "icon"));
    TextStyleM.setTextStyle(shipNameLabel, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_GOLD_YELLOW, true, nil, nil, nil, nil, nil, true);
    shipNameLabel:setString(shipName);
    convertTextToArtWord(shipNameLabel, "images/ui/text_mask/text_mask3.png", TextStyleM.TEXT_COLOR_DARK_BROWN,
       TextStyleM.TEXT_OUTLINE_COLOR_DARK);

    -- 使用带沙影的飞船
    shipNode:removeAllChildren();
    shipNode:stopAllActions();
    local shipIcon = ccui.ImageView:create();
    shipIcon:loadTexture(getAirShipImgPath(NewAirShipM.query(shipId, "icon")));
    shipIcon:setScale(0.9);
    shipNode:addChild(shipIcon);

    -- 飞艇悬浮
    playFluctuateAnima(shipNode, 1, 5);

    -- 点击飞船进入飞艇操作界面
    local function onShipClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            local uiForm = UISkyCity.create();
            UIMgr.getCurrentScene():addForm(uiForm);
        end
    end
    AddTouchEventListener(panel, onShipClick);
end

-- 检查采集部分
function UISkyCityRuins:checkCollcetShow()
    local storeNode = findChildByName(self.node, "bg/store");
    local storePanel = findChildByName(self.node, "bg/store_panel");
    local infoNode = findChildByName(self.node, "bg/info");
    local revengePanel = findChildByName(self.node, "bg/revenge_panel")
    local workerId = SkyRelicFunctionM.getIdsByRule("worker");
    local containerId = SkyRelicFunctionM.getIdsByRule("container");

    if SkyRelicFunctionM.getLevel(workerId) < 1
        or SkyRelicFunctionM.getLevel(containerId) < 1 then
        storeNode:setVisible(false);
        storePanel:setVisible(false);
        infoNode:setVisible(false);
        revengePanel:setVisible(false);
    else
        infoNode:setVisible(true);
        revengePanel:setVisible(true);

        if not storeNode:isVisible() then
            self:playBuildCollectEffect();
        else
            storeNode:setVisible(true);
            storePanel:setVisible(true);
        end
    end
end

-- 播放建造动画
function UISkyCityRuins:playBuildCollectEffect()
    local storeNode = findChildByName(self.node, "bg/store");
    local storePanel = findChildByName(self.node, "bg/store_panel");
    storeNode:setVisible(false);
    storePanel:setVisible(true);
    local _, effect = playEffect(storePanel, 1151, 90, 70);

    local function callback()
        storeNode:setVisible(true);
        storePanel:removeAllChildren();
    end

    performWithDelay(self, callback, 1);
end

-- 遗迹采集部分
function UISkyCityRuins:redrawRuins()
    local storeNode    = findChildByName(self.node, "bg/store");
    local percentLabel = findChildByName(storeNode, "percent");
    local bubbleNode   = findChildByName(storeNode, "bubble");
    local effectNode   = findChildByName(storeNode, "effect_node");
    local bubbleBg     = findChildByName(bubbleNode, "bg");
    bubbleNode:setVisible(false);

    local icon = findChildByName(bubbleNode, "icon");
    local classId = SkyResourceM.queryByAlias("relic_scrap", "class_id");
    icon:loadTexture(getItemIconPath(ItemM.query(classId, "icon")));
    TextStyleM.setTextStyle(percentLabel, TextStyleM.TEXT_SIZE_SMALL, TextStyleM.TEXT_COLOR_BRIGHT_BLUE, true);

    -- 百分比/根据speed回调
    local function setPercent(showNum)
        local nowCount = SkyRelicM.getMyRelicInfo("resource")["scrap"] or 0;
        local storeSize = ME.user:queryAttrib("relic_store");
        local percentNum;

        -- 计算百分比值
        if storeSize <= 0 then
            percentNum = 0;
        else
            percentNum = showNum or math.ceil(nowCount * 100 / storeSize);
        end
        local percentText = string.format(getLocStr("percent"), percentNum);
        percentLabel:setString(percentText);

        if showNum and showNum == 0 then
            local delay = 0;
            if effectNode.imgNode then
                -- 挂点隐藏
                local fadeOut = cc.FadeOut:create(0.5);
                effectNode.imgNode:runAction(fadeOut)
                delay = 0.5;
                effectNode.lastEffect = 0;
                effectNode.imgNode = nil;

                if effectNode.exImg then
                    -- 散落的隐藏
                    local fadeOut = cc.FadeOut:create(0.5);
                    effectNode.exImg:runAction(fadeOut);
                    effectNode.exImg = nil;
                end
            end
            local function func()
                -- 播放空光效
                effectNode:removeAllChildren();
                effectNode.imgNode = nil;
                effectNode.exImg = nil;
                playEffect(effectNode, 1833, 27, -95);
            end
            performWithDelay(self, func, delay);
            return;
        end

        -- 根据当前收获百分比更换矿车图标
        -- 按照当前比例选取光效(超过1%即显示little)
        local rangeInfo = {{90, 1836, "full"}, {50, 1835, "lot"}, {1, 1834, "little"}, {0, 1833}};
        for _, info in pairs(rangeInfo) do
            if percentNum >= info[1] then
                if effectNode.lastEffect == info[2] then
                    -- 就是当前光效，不处理
                    return;
                end

                effectNode:removeAllChildren();
                effectNode.imgNode = nil;
                effectNode.exImg = nil;
                local _, effect = playEffect(effectNode, info[2], 27, -95);
                effectNode.lastEffect = info[2];

                if not info[3] then
                    -- 后面的不用做
                    return;
                end

                local imgNode = findChildByName(effect, "img_node/SpriteObject");
                local imgName = info[3] .. "1";
                local exName = "overflow1";

                -- 金币挖掘技术
                local funcId = SkyRelicFunctionM.getIdsByRule("money_worker");
                local level  = SkyRelicFunctionM.getLevel(funcId);
                if level > 0 then
                    imgName = info[3] .. "2";
                    exName = "overflow2";
                end

                imgNode:setTexture(getRelicIcon(imgName));
                effectNode.imgNode = imgNode;
                effectNode.imgNode:setOpacity(255);

                if info[3] == "full" then
                    -- 满的，额外图片
                    local exImg = ccui.ImageView:create(getRelicIcon(exName));
                    effectNode:addChild(exImg);
                    exImg:setPosition(cc.p(120, -45));
                    exImg:setLocalZOrder(-1);
                    effectNode.exImg = exImg;
                    effectNode.exImg:setOpacity(255);
                end
                break;
            end
        end
    end

    local function tick()
        self.tick = true;
        setPercent();
        local durTime = math.min(10, SkyRelicM.getGatherUnitTime());
        -- 检查信息气泡
        if SkyRelicM.canCollect() then
            if not bubbleNode:isVisible() then
                bubbleNode:setVisible(true);
                -- 气泡轻微收缩
                bubbleNode:stopAllActions();
                playBubbleAnima(bubbleNode, false, 0.88);
            end
        else
            bubbleNode:stopAllActions();
            bubbleNode:setVisible(false);
        end
        performWithDelay(self, tick, durTime);
    end

    -- 调用一次即可
    if not self.tick then
        tick();
    end

    local storePanel = findChildByName(self.node, "bg/store_panel");
    storePanel:setVisible(true);
    local function onBubbleClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_click");
            if SkyRelicM.canCollect() then
                -- 收集
                SkyRelicM.collectRelic();
                setPercent(0);
                bubbleNode:setVisible(false);
            else
                local workerId = SkyRelicFunctionM.getIdsByRule("worker");
                local containerId = SkyRelicFunctionM.getIdsByRule("container");
                if SkyRelicFunctionM.getLevel(workerId) < 1 then
                    -- 没有矿工
                    alert(getLocStr("relic_no_worker"));
                elseif SkyRelicFunctionM.getLevel(containerId) < 1 then
                    -- 没有矿车
                    alert(getLocStr("relic_no_container"));
                else
                    -- 正在努力发掘提示
                    alert(getLocStr("hard_working"));
                end
            end
        end
    end
    AddTouchEventListener(bubbleBg, onBubbleClick);
    AddTouchEventListener(storePanel, onBubbleClick);
end

-- 检查挖掘工重绘
function UISkyCityRuins:checkSlimes()
    if self.hasWorker then
        -- 已经有挖掘工了
        return;
    end

    -- 没有挖掘工，尝试调一次首次进入
    self:redrawSlimes(true);
end

-- 跳跃的冈布奥
function UISkyCityRuins:redrawSlimes(firstIn)
    local workerId = SkyRelicFunctionM.getIdsByRule("worker");
    if SkyRelicFunctionM.getLevel(workerId) < 1 then
        -- 没有挖掘工
        self.hasWorker = false;
        return;
    end

    local iconList = {};
    if self.iconList then
        iconList = self.iconList;
    else
        local default = "images/ui/workshop/new_slime.png";
        local worker1 = "images/ui/workshop/worker1.png";
        local worker2 = "images/ui/workshop/worker2.png";
        local worker3 = "images/ui/workshop/worker3.png";

        for i = 1, TOTAL_WORKERS - 3 do
            table.insert(iconList, default);
        end

        table.insert(iconList, worker1);
        table.insert(iconList, worker2);
        table.insert(iconList, worker3);
        table.randomSort(iconList);
        self.iconList = iconList;
    end

    self.hasWorker = true;

    if firstIn then
        -- 跳进来
        self:workerFirstRunIn();
        return;
    end

    -- 之所以分两个节点是因为
    -- 不同位置和矿车前后遮挡问题
    local posParent1 = findChildByName(self.node, "bg/normal_pos1");
    local posParent2 = findChildByName(self.node, "bg/normal_pos2");

    -- 创建阴影
    for i = 1, TOTAL_WORKERS do
        -- 找到父节点
        local posParent = iif((i == 1 or i == 2), posParent1, posParent2);

        local pos = posParent:getChildByName("worker"..i);
        local shadow = ccui.ImageView:create();
        shadow:loadTexture("images/ui/workshop/shadow2.png", 1);
        shadow:setScale(0.8);
        posParent:addChild(shadow);
        pos.shadow = shadow;
        shadow:setVisible(true);
    end

    -- 工匠冈布奥
    for i = 1, TOTAL_WORKERS do
        -- 找到父节点
        local posParent = iif((i == 1 or i == 2), posParent1, posParent2);

        local shadowOffset = self:getWorkerShadowOffset(iconList[i]) or {0, 0};
        local pos = posParent:getChildByName("worker"..i);
        local slime = ccui.ImageView:create();
        slime:loadTexture(iconList[i], 1);
        slime:setScale(0.8);
        slime:setPosition(cc.p(pos:getPosition()));
        posParent:addChild(slime);

        local direction = iif(math.random(1, 2)==1, 1, -1);
        if pos.direction then
            direction = pos.direction;
        end

        if direction == 1 then
            -- 设置阴影位置
            pos.shadow:setPosition(cc.p(pos:getPositionX() - shadowOffset[1],
                pos:getPositionY() - shadowOffset[2] + 2));
        else
            -- 设置阴影位置
            pos.shadow:setPosition(cc.p(pos:getPositionX() + shadowOffset[1],
                pos:getPositionY() - shadowOffset[2] + 2));
            -- 转向
            slime:setScaleX(-0.8);
        end

        -- 播放跳跃动画
        slimeJumpAnimation(slime, cc.p(-0, 0), cc.p(-0, 0), cc.p(300, 800), cc.p(5, 15));
    end

    -- 特殊动画冈布奥
    local effectList = {1832, 1830, 1831};
    local offsetList = {{125, -125}, {125, -142}, {90, -120}};
    local effectParent = findChildByName(self.node, "bg/effect_pos");
    for i = 1, EFFECT_WORKERS do
        local pos = effectParent:getChildByName("pos"..i);
        local offset = offsetList[i];
        pos:stopAllActions();
        pos:removeAllChildren();
        local _, effectNode = playEffect(pos, effectList[i], offset[1], offset[2], nil, 0.8);
        if i == 2 then
            -- 放大镜冈布奥翻转一下
            pos:setScaleX(-1);
        end
    end
end

-- 注册事件处理回调函数
function UISkyCityRuins:registerEventCallback()
    -- 界面析构后，需要清理下
    self:registerScriptHandler(function(eventType)
        if eventType == "exit" then
            EventMgr.removeAll("UISkyCityRuins");
            if UIMgr.getCurrentScene().mainMap then
                UIMgr.getCurrentScene().mainMap:show();
            end
        elseif eventType == "enter" then
            UIMgr.getCurrentScene().mainMap:hide();
        end
    end);

    -- 注册获得焦点的回调
    EventMgr.register("UISkyCityRuins", event.FOCUS_CHANGED, function(para)
        if para["get"] == "UISkyCityRuins" then
            self:showBottomMenu(true);
            UIMgr:getCurrentScene().topMenu:show(TOPMENU_FRAME_MONEY , TOPMENU_FRAME_RUINS_SCRAP, TOPMENU_FRAME_HEAD_AIRSHIP);
            -- 重新检查提示
            self:checkBtnHint();
            -- 检查采集显示
            self:checkCollcetShow();
            -- 检查工匠冈布奥
            self:checkSlimes();
        elseif para["lose"] == "UISkyCityRuins" then
            self:showBottomMenu(false);
        end
    end);

    -- 复仇记录更新
    EventMgr.register("UISkyCityRuins", event.REVENGE_LIST_UPDATE, function(para)
        -- 检查复仇记录
        self:redrawInfo();
    end);

    -- 状态飞船刷新
    EventMgr.register("UISkyCityRuins", event.USER_INFO_UPDATED, function(args)
        if args == "active_airship" then
            -- 重绘
            self:redrawAirShip();
        elseif args == "relic_info" then
            -- 重绘
            self:redrawDefence();
            self:redrawInfo();
            self:redrawRuins();
        end
    end);

    -- 升级
    EventMgr.register("UISkyCityRuins", event.RELIC_DEVELOP, function(para)
        local id = para.id;
        local funcId = SkyRelicFunctionM.getIdsByRule("permit");
        if id == funcId then
            self:redrawInfo();
            self:checkPermitBtn();
        end
    end);

    -- 掠夺地图刷新事件
    EventMgr.register("UISkyCityRuins", event.RELIC_REFRESH_MAP, function(para)
        -- 检查气泡提示
        self:checkBtnHint();
    end);

    -- 采集结果
    EventMgr.register("UISkyCityRuins", event.RELIC_COLLECT_RESOURCE, function(para)
        -- 播放奖励飘字
        self:showCollectTip(para.bonus);
    end);
end

-- 播放奖励
function UISkyCityRuins:showCollectTip(bonus)
    local storeNode = findChildByName(self.node, "bg/store");
    storeNode.gainItemList = {};

    for _, perBonus in pairs(bonus) do
        local name = "";
        if perBonus[1] == 1 then
            -- 物品
            name = ItemM.query(perBonus[2], "name");
        elseif perBonus[1] == 2 then
            -- 属性
            name = FieldsM.query(perBonus[2], "name");
        end
        -- 拼接提示
        local tip = string.format(getLocStr("item_bonus_format"), name, perBonus[3])
        table.insert(storeNode.gainItemList, tip);
    end

    local function createTextFunc(color, str)
        local text = ccui.Text:create();
        text:setFontName(getLocFontName());
        text:setFontSize(36);
        text:setString(str);
        text:setTextColor(color);
        text:setAnchorPoint(cc.p(0.5, 0.5));
        local outlineColor = TextStyleM.TEXT_COLOR_DARK_BROWN;
        text:enableOutline(cc.c4b(outlineColor[1], outlineColor[2], outlineColor[3], 255), 2);
        text:enableShadow(TextStyleM.TEXT_OUTLINE_COLOR_DARK, cc.size(3, -3));
        text:getVirtualRenderer():setAdditionalKerning(getLocKerning() -4);
        text:setScale(0.8);
        return text;
    end
    showItemName(storeNode, TextStyleM.TEXT_COLOR_BRIGHT_YELLOW, 150,
        125, createTextFunc);
end

-- 隐藏/显示bg部分节点
function UISkyCityRuins:hideBgNodes(visible)
    local bg =  findChildByName(self.node, "bg");
    local hideNodes = {"defence", "store", "info", "normal_pos1", "normal_pos2",
        "ship_panel", "ship", "ship_name", "effect_pos"};
    for _, node in pairs(bg:getChildren()) do
        if table.indexOf(hideNodes, node:getName()) ~= -1 then
            node:setVisible(visible);
        end
    end
end

-- 隐藏底部菜单
function UISkyCityRuins:showBottomMenu(visible)
    local BT = findChildByName(self.node, "BT");
    BT:setVisible(visible);
end

-- 检查按钮提示气泡
function UISkyCityRuins:checkBtnHint()
    -- 有可以升级的
    local needBuildHint = false;
    if SkyRelicFunctionM.needShowBubbleForIndex(1)
        or SkyRelicFunctionM.needShowBubbleForIndex(2)
        or SkyRelicFunctionM.needShowBubbleForIndex(3) then
        needBuildHint = true;
    end
    local btnBuildHint = findChildByName(self.node, "BT/build_btn/hint");
    if needBuildHint then
        btnBuildHint:setVisible(true);
        playBubbleAnima(btnBuildHint, false);
    else
        btnBuildHint:setVisible(false);
    end

    -- 计算当前可以掠夺的数量(玩家/彩蛋/boss)
    local canRelicNum = SkyRelicM.getRelicElementNum();
    local btnRelicHint = findChildByName(self.node, "BT/punder_btn/hint");
    checkBlueBubbleStatus(btnRelicHint, canRelicNum);
end

-- 注册点击事件
function UISkyCityRuins:registerTouchEvent()
    -- 注册返回按钮点击事件
    local btnBack = findChildByName(self.node,"BT/btn_back");
    local function onBackClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_return");
            -- 关闭当前界面
            UIMgr.getCurrentScene():removeFormByName("UISkyCityRuins");
        end
    end
    AddBackEventHandler(self, btnBack, onBackClick);
    TextStyleM.setTextStyle(btnBack, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnBack:setTitleText(getLocStr("btn_text_back"));

    -- 扩建按钮
    local btnBuild = findChildByName(self.node, "BT/build_btn");
    local function onBuildClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_click");
            local uiRelicStrengthen = UIRelicStrengthen.create("relic");
            UIMgr.getCurrentScene():addForm(uiRelicStrengthen);
        end
    end
    AddTouchEventListener(btnBuild, onBuildClick);
    TextStyleM.setTextStyle(btnBuild, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnBuild:setTitleText(getLocStr("btn_text_build2"));

    -- 掠夺按钮
    local btnPunder = findChildByName(self.node, "BT/punder_btn");
    local function onPunderClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("button_click");
            local uiForm = UISkyRelicMain.create("relic");
            UIMgr.getCurrentScene():addForm(uiForm);
        end
    end
    AddTouchEventListener(btnPunder, onPunderClick);
    TextStyleM.setTextStyle(btnPunder, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnPunder:setTitleText(getLocStr("btn_text_punder"));
end

-- 检查按钮是否显示
function UISkyCityRuins:checkPermitBtn()
    local btnPunder = findChildByName(self.node, "BT/punder_btn");
    local funcId = SkyRelicFunctionM.getIdsByRule("permit");
    if SkyRelicFunctionM.getLevel(funcId) < 1 then
        -- 没有掠夺许可证
        btnPunder:setVisible(false);
    else
        btnPunder:setVisible(true);
    end
end

-- 获取工匠阴影偏移值
function UISkyCityRuins:getWorkerShadowOffset(iconPath)
    if iconPath == "images/ui/workshop/worker1.png" then
        return workerShadowOffset[1];
    elseif iconPath == "images/ui/workshop/worker2.png" then
        return workerShadowOffset[2];
    elseif iconPath == "images/ui/workshop/worker3.png" then
        return workerShadowOffset[3];
    else
        return nil;
    end
end

-- 工匠首次跳进来
function UISkyCityRuins:workerFirstRunIn()
    -- 之所以分两个节点是因为
    -- 不同位置和矿车前后遮挡问题
    local posParent1 = findChildByName(self.node, "bg/normal_pos1");
    local posParent2 = findChildByName(self.node, "bg/normal_pos2");

    -- 等下需要干掉的所有节点TODO
    local removeNode = {};
    local iconList = self.iconList;
    local shadowList = {};

    -- 创建阴影
    for i = 1, TOTAL_WORKERS do
        -- 找到父节点
        local posParent = iif((i == 1 or i == 2), posParent1, posParent2);
        local pos = posParent:getChildByName("worker"..i);
        local shadow = ccui.ImageView:create();
        shadow:loadTexture("images/ui/workshop/shadow2.png", 1);
        shadow:setScale(0.8);
        posParent:addChild(shadow);
        pos.shadow = shadow;
        shadow:setVisible(true);
        shadowList[i] = shadow;
    end

    -- 工匠冈布奥
    for i = 1, TOTAL_WORKERS do
        -- 找到父节点
        local posParent = iif((i == 1 or i == 2), posParent1, posParent2);
        local direction = iif((i == 1 or i == 2), 1, -1);

        local shadowOffset = self:getWorkerShadowOffset(iconList[i]) or {0, 0};
        local pos = posParent:getChildByName("worker"..i);
        local slime = ccui.ImageView:create();
        slime:loadTexture(iconList[i], 1);
        slime:setScale(0.8);
        slime.shadow = shadowList[i];

        -- 避免等下转方向了
        -- 会给人感觉闪一下
        -- 第一次方向固定
        pos.direction = direction;

        -- 起点
        local oriPos = iif((i == 1 or i == 2), cc.p(-360, pos:getPositionY()), cc.p(400, pos:getPositionY()));
        -- 影子起点
        local shadowPosX = iif(direction > 0, -360 - shadowOffset[1], 400 + shadowOffset[1]);
        local shadowPos = cc.p(shadowPosX, pos:getPositionY() + 4);
        slime:setPosition(oriPos);
        slime.shadow:setPosition(shadowPos);
        -- 终点
        local targetPos = cc.p(pos:getPosition());
        posParent:addChild(slime);

        -- 动画
        self:complexJumpEffect(slime, targetPos, shadowOffset);
    end

    -- 动画冈布奥
    -- 应该不会互相遮挡，不分开处理了
    local effectParent = findChildByName(self.node, "bg/effect_pos");
    for i = 1, EFFECT_WORKERS do
        local pos = effectParent:getChildByName("pos"..i);
        -- 阴影
        local shadow = ccui.ImageView:create();
        shadow:loadTexture("images/ui/workshop/shadow2.png", 1);
        shadow:setScale(0.8);
        effectParent:addChild(shadow);

        -- 冈布奥
        local slime = ccui.ImageView:create(getRelicIcon("worker" .. i));
        slime.shadow = shadow;
        effectParent:addChild(slime);

        local effectOffset = {{20, 12}, {8, 0}, {10, 0}};
        local targetOffset = {{-15,-25}, {-8,-15}, {18, -10}};
        local direction = iif((i == 1 or i == 2), -1, 1);
        local shadowOffset = effectOffset[i];
        local posOffset = targetOffset[i];
        -- 起点
        local oriPos = iif((i == 1 or i == 2), cc.p(400, pos:getPositionY()), cc.p(-360, pos:getPositionY()));
        -- 影子起点
        local shadowPosX = iif(direction < 0, 400 + shadowOffset[1], -360 - shadowOffset[1]);
        local shadowPos = cc.p(shadowPosX, pos:getPositionY() + 4 + shadowOffset[2]);
        -- 终点
        local targetPos = cc.p(pos:getPositionX() + posOffset[1], pos:getPositionY() + posOffset[2]);
        slime:setPosition(oriPos);
        slime.shadow:setPosition(shadowPos);
        -- 动画
        self:complexJumpEffect(slime, targetPos, shadowOffset);
    end

    -- 回调动画
    local function callback()
        -- 先清理一下
        local removeParent = {posParent1, posParent2};
        local leftNode = {"worker1", "worker2", "worker3", "worker4"};
        for _, posParent in pairs(removeParent) do
            for _, childNode in pairs(posParent:getChildren()) do
                if table.indexOf(leftNode, childNode:getName()) == -1 then
                    posParent:removeChild(childNode);
                end
            end
        end

        leftNode = {"pos1", "pos2", "pos3"};
        for _, childNode in pairs(effectParent:getChildren()) do
            if table.indexOf(leftNode, childNode:getName()) == -1 then
                effectParent:removeChild(childNode);
            end
        end

        self:redrawSlimes();
    end

    performWithDelay(self, callback, 3.5);
end

-- 复杂的跳跃动画
function UISkyCityRuins:complexJumpEffect(node, targetPos, shadowOffset, durTime)
    local oriPos = cc.p(node:getPosition());
    -- 左入为1，右入为-1
    local direction = iif((oriPos.x - targetPos.x < 0), 1, -1);

    local offsetX = oriPos.x - targetPos.x;
    local jumpNum = math.abs(offsetX / 50);

    -- 最大扭曲角度
    local MAX_SKEW_DEGREE = 5;
    -- 转向
    local xScale = direction*0.8;
    -- 计算扭曲因子
    local skewFactor = math.floor(MAX_SKEW_DEGREE * (targetPos.x - oriPos.x) / 20);
    -- 距离比较大需要修正
    skewFactor = iif(skewFactor > 0, math.min(skewFactor, 5), math.max(skewFactor, -5));
    -- 把锚点设置为下底边中心
    node:setAnchorPoint(cc.p(0.5, 0));
    -- 右上方向扭曲
    local skewRight = cc.EaseIn:create(cc.SkewBy:create(0.05, skewFactor, 0), 2.5);
    -- 压缩
    local compressDown1 = cc.EaseIn:create(cc.ScaleTo:create(0.025, xScale, 0.7), 2.5);
    -- 拉伸
    local stretchUp1 = cc.EaseOut:create(cc.ScaleTo:create(0.05, xScale, 0.9), 2.5);
    -- 起跳参数
    local jumps = durTime or 3.0;
    local height = 10;
    -- 动画
    local jumpBy = cc.JumpTo:create(jumps, targetPos, height, jumpNum);
    -- 左上方向扭曲
    local skewLeft = cc.EaseOut:create(cc.SkewBy:create(0.2, -skewFactor, 0), 2.5);
    -- 压缩
    local compressDown2 = cc.EaseOut:create(cc.ScaleTo:create(0.1, xScale, 0.75), 2.5);
    -- 站直
    local skewVertical = cc.EaseOut:create(cc.SkewBy:create(0.05, 0, 0), 2.5);
    -- 拉伸还原
    local stretchUp2 = cc.EaseOut:create(cc.ScaleTo:create(0.05, xScale, 0.8), 2.5);

    -- 根据方向进行跳跃
    node:stopAllActions();
    if targetPos.x - oriPos.x < 0 then
        node:runAction(cc.Sequence:create(compressDown1, skewRight, stretchUp1, jumpBy, compressDown2, skewLeft, stretchUp2, skewVertical));
    else
        node:runAction(cc.Sequence:create(compressDown1, skewLeft, stretchUp1, jumpBy, compressDown2, skewRight, stretchUp2, skewVertical));
    end

    -- 处理影子
    local shadowTargetPos = targetPos;
    if direction > 0 then
        shadowTargetPos.x = targetPos.x - shadowOffset[1];
    else
        shadowTargetPos.x = targetPos.x + shadowOffset[1];
    end
    shadowTargetPos.y = shadowTargetPos.y + 4 + shadowOffset[2];

    -- 影子的位移
    if node.shadow then
        local jumpBy2 = cc.JumpTo:create(jumps, cc.p(shadowTargetPos.x , shadowTargetPos.y - 1), 0, jumpNum);
        node.shadow:stopAllActions();
        if targetPos.x - oriPos.x < 0 then
            node.shadow:runAction(cc.Sequence:create(cc.DelayTime:create(0.1), jumpBy2));
        else
            node.shadow:runAction(cc.Sequence:create(cc.DelayTime:create(0.3), jumpBy2));
        end
    end
end